#include "td4550serialthread.h"
#include <QDebug>
//#include <QMessageBox.h>
#include <QString>
#include<QTimer>
//#include<QTime>
//#include <synchapi.h>
//#include "tunkia.h"
#include "tool.h"

TD4550SerialThread::TD4550SerialThread()
{
  //   qDebug()<<"TD4550线程开启了";
     错误类型=0;
     串口状态=0;
     BaudTime=50;
     comConj<<0<<0<<0<<0<<0;

     timer1 = new QTimer(this);
     QObject::connect(timer1,&QTimer::timeout,this,[=](){TD4550SerialThread::confirmTD4550();});

     TD校准步骤=1;
   //  timer2 = new QTimer(this);//校准步骤用
   //  QObject::connect(timer2,&QTimer::timeout,this,[=](){TD4550SerialThread::TD4550Step();});

     qDebug()<<"4550当前线程开启_构造"<<QThread::currentThread();

     TD4550输出={};

}


//getConj得到串口配置后再交由openConj打开串口
void TD4550SerialThread::getConj(QString comNo,QList<int> comConj)
{
    TD校准步骤=1;
    接收数据="";
    检查次数=1;
    检查步骤=1;
    TD4550输出={220000,220000,220000,0,0,0, 0,0,0, 0,0,0,  0,0,0,  0,0,0};

 //   qDebug()<<"4550当前线程"<<QThread::currentThread();
    if(串口状态==0) openConj(comNo,comConj);

    if(串口状态==3)
    {
        return;
        //emit TD4550State("TD4550串口不能打开",false,100);
    }



    //等于1即是打开串口了, 再发送命令确认仪器连接正常
    if(串口状态==1)
    {
        emit TD4550State("正在连接TD4550",true,0);
        //发送"OUT|IA=0", 要求返回的是"OUT=00"
        sendData(天恒生成帧("PARW|OUTSW=ON"));//sleepMsec(200);
      //  sendData(天恒生成帧("OUT|UA=220|UB=220|UC=220|PHUAIA=0|PHUBIB=0|PHUCIC=0|IA=0|IB=0|IC=0"));
        timer1->start(2000);
   //     qDebug()<<"timer1定时器开启";
    }
}

//确认与TD4550连接成功
void TD4550SerialThread::confirmTD4550()
{
    //disconnect(timer1,&QTimer::timeout,this,[=](){TD4550SerialThread::confirmTD4550();});//无法这样取消定时器与槽函数的连接, 为什么??
    timer1->stop();
 //   qDebug()<<"TD455执行到这1";

//从这开始校准,
  //  qDebug()<<"TD4550接收数据"<<接收数据;
    //if(接收数据=="OUT=00")
    if(接收数据=="PARW=00")
    {

        emit TD4550State("开始校准",true,1);
      //  sendData(天恒生成帧("PARW|OUTSW=ON"));sleepMsec(200);
        sendData(天恒生成帧("OUT|UA=220|UB=220|UC=220|PHUAIA=0|PHUBIB=0|PHUCIC=0|IA=0|IB=0|IC=0"));
        return;
    }
    //if(接收数据.length()<2){ emit TD4550State("TD4550未接收到数据",false,100); return;}

    if(错误类型==0) { emit TD4550State("TD4550未接收到数据",false,100); return;}
    if(错误类型==2) { emit TD4550State("TD4550校验错误",false,100);    return;}
    if(错误类型==10){ emit TD4550State("TD4550接收的数据长度错误",false,100);return;}

}

void TD4550SerialThread::calibrate_TD4550(int 校准步骤)
{
    qDebug()<<"TD4550校准步骤gg"<<校准步骤;


    if(校准步骤==101){//只能由主线程发送 校准步骤==101, 表示停止校准, 关闭串口
         qDebug()<<"TD4550串口状态"<<串口状态;
         if(串口状态==1||串口状态==3)
         {
             if(串口状态==1)
             {
             sendData(天恒生成帧("OUT|IA=0|IB=0|IC=0"));sleepMsec(200);
             sendData(天恒生成帧("PARW|ACIRG=AUTO"));sleepMsec(200);
             sendData(天恒生成帧("PARW|OUTSW=OFF"));sleepMsec(200);
             }
             //simpleSerial->clear();
             simpleSerial->close();
             simpleSerial->deleteLater();//删除对象后，任何地方此对象都不存在，不能再被任何函数包含进去。
         }
        disconnect(simpleSerial,&QSerialPort::readyRead,this,&TD4550SerialThread::waitRead);

        串口状态=0;
     //   qDebug()<<"TD4550当前线程"<<QThread::currentThread();
        if(TD校准步骤==12) emit TD4550State("TD4550校准完成",false,101);
        if(TD校准步骤<12) emit TD4550State("TD4550校准异常结束",false,101);
        TD校准步骤=1;
        return;
    }

    TD校准步骤=校准步骤;

//由以下函数执行相应的校准步骤
  //  timer2->start(30000);//不停地检查源的输出是否达到要求

//qDebug()<<"TD校准步骤bbb"<<TD校准步骤;

    switch(TD校准步骤)
    {
    case 2: sendData(天恒生成帧("PARW|ACIRG=AC1A"));sleepMsec(200);
            sendData(天恒生成帧("OUT|UA=220|UB=220|UC=220|PHUAIA=0|PHUBIB=0|PHUCIC=0|IA=0|IB=0|IC=0"));      break;//[cal_0] 初始化   timer2->start(5000);

    case 3: sendData(天恒生成帧("PARW|ACIRG=AC100A"));sleepMsec(200);
            sendData(天恒生成帧("OUT|UA=220|UB=220|UC=220|PHUAIA=0|PHUBIB=0|PHUCIC=0|IA=80|IB=80|IC=80"));   break;//[cal_1] 80A,PF=1   timer2->start(25000);

    case 4: sendData(天恒生成帧("PARW|ACIRG=AC100A"));sleepMsec(200);
            sendData(天恒生成帧("OUT|UA=220|UB=220|UC=220|PHUAIA=60|PHUBIB=60|PHUCIC=60|IA=80|IB=80|IC=80"));break;//[cal_2] 80A,PF=0.5   timer2->start(25000);

    case 5: sendData(天恒生成帧("OUT|IA=0|IB=0|IC=0"));sleepMsec(200);
            sendData(天恒生成帧("PARW|ACIRG=AC50A"));sleepMsec(200);
            sendData(天恒生成帧("OUT|UA=220|UB=220|UC=220|PHUAIA=0|PHUBIB=0|PHUCIC=0|IA=20|IB=20|IC=20"));   break;//[cal_3] 20A,PF=1     timer2->start(18000);

    case 6: sendData(天恒生成帧("OUT|IA=0|IB=0|IC=0"));sleepMsec(200);
            sendData(天恒生成帧("PARW|ACIRG=AC50A"));sleepMsec(200);
            sendData(天恒生成帧("OUT|UA=220|UB=220|UC=220|PHUAIA=60|PHUBIB=60|PHUCIC=60|IA=20|IB=20|IC=20"));break;//[cal_4] 20A,PF=0.5    timer2->start(18000);

    case 7: sendData(天恒生成帧("OUT|IA=0|IB=0|IC=0"));sleepMsec(200);
            sendData(天恒生成帧("PARW|ACIRG=AC5A"));sleepMsec(200);
            sendData(天恒生成帧("OUT|UA=220|UB=220|UC=220|PHUAIA=0|PHUBIB=0|PHUCIC=0|IA=5|IB=5|IC=5"));      break;//[cal_5] 5A,PF=1    timer2->start(18000);

    case 8: sendData(天恒生成帧("OUT|IA=0|IB=0|IC=0"));sleepMsec(200);
            sendData(天恒生成帧("PARW|ACIRG=AC5A"));sleepMsec(200);
            sendData(天恒生成帧("OUT|UA=220|UB=220|UC=220|PHUAIA=60|PHUBIB=60|PHUCIC=60|IA=5|IB=5|IC=5"));   break;//[cal_6] 5A,PF=0.5   timer2->start(18000);

    case 9: sendData(天恒生成帧("OUT|IA=0|IB=0|IC=0"));sleepMsec(200);
            sendData(天恒生成帧("PARW|ACIRG=AC2A"));sleepMsec(200);
            sendData(天恒生成帧("OUT|UA=220|UB=220|UC=220|PHUAIA=0|PHUBIB=0|PHUCIC=0|IA=1|IB=0|IC=0"));      break;//[cal_7] 1A,漏电    timer2->start(15000);

    case 10:sendData(天恒生成帧("OUT|IA=0|IB=0|IC=0"));sleepMsec(200);
            sendData(天恒生成帧("PARW|ACIRG=AC2A"));sleepMsec(200);
            sendData(天恒生成帧("OUT|UA=220|UB=220|UC=220|PHUAIA=60|PHUBIB=60|PHUCIC=60|IA=2|IB=2|IC=2"));   break;//[cal_8] 2A,偏置    timer2->start(15000);

    case 11:sendData(天恒生成帧("OUT|IA=0|IB=0|IC=0"));sleepMsec(200);
            sendData(天恒生成帧("PARW|ACIRG=AUTO"));sleepMsec(200);
            sendData(天恒生成帧("OUT|UA=220|UB=220|UC=220|PHUAIA=0|PHUBIB=0|PHUCIC=0|IA=0|IB=0|IC=0"));      break;//输出全设0,停止校准    timer2->start(5000);

    case 12:sendData(天恒生成帧("PARW|OUTSW=OFF"));emit TD4550State("全部校准完成",false,100);break;//关闭输出

    default: emit TD4550State("全部校准完成",false,100);
    }

    //源的标准值
    switch(TD校准步骤)
    {
    case 2: TD4550输出={220000,220000,220000,     0,     0,     0,       0,       0,       0,      0,      0,      0,       0,       0,       0,       0,       0,       0};break;
    case 3: TD4550输出={220000,220000,220000, 80000, 80000, 80000,17600000,17600000,17600000,1000000,1000000,1000000,       0,       0,       0,17600000,17600000,17600000};break;
    case 4: TD4550输出={220000,220000,220000, 80000, 80000, 80000, 8800000, 8800000, 8800000, 500000, 500000, 500000,15242047,15242047,15242047,17600000,17600000,17600000};break;
    case 5: TD4550输出={220000,220000,220000, 20000, 20000, 20000, 4400000, 4400000, 4400000,1000000,1000000,1000000,       0,       0,       0, 4400000, 4400000, 4400000};break;
    case 6: TD4550输出={220000,220000,220000, 20000, 20000, 20000, 2200000, 2200000, 2200000, 500000, 500000, 500000, 3810512, 3810512, 3810512, 4400000, 4400000, 4400000};break;
    case 7: TD4550输出={220000,220000,220000,  5000,  5000,  5000, 1100000, 1100000, 1100000,1000000,1000000,1000000,       0,       0,       0, 1100000, 1100000, 1100000};break;
    case 8: TD4550输出={220000,220000,220000,  5000,  5000,  5000,  550000,  550000,  550000, 500000, 500000, 500000,  952628,  952628,  952628, 1100000, 1100000, 1100000};break;
    case 9: TD4550输出={220000,220000,220000,  1000,    0,      0,  220000,       0,       0,1000000,      0,      0,       0,       0,       0, 2200000,       0,       0};break;
    case 10:TD4550输出={220000,220000,220000,  2000,  2000,  2000,  220000,  220000,  220000, 500000, 500000, 500000,  381051,  381051,  381051,  440000,  440000,  440000};break;
    case 11:TD4550输出={220000,220000,220000,     0,     0,     0,       0,       0,       0,      0,      0,      0,       0,       0,       0,       0,       0,       0};break;
   // default: break;
    }


   qDebug()<<"TD校准步骤TDTD"<<TD校准步骤;
}



//不停地检查源的输出是否达到要求
void TD4550SerialThread::TD4550Step()
{
    qDebug()<<"TD4550在30秒后";
    QString 校准信息="源的步骤 "+QString::number(TD校准步骤,10)+"已准备好。";

    switch(TD校准步骤)
    {
    case 2 :校准信息 +="220V, 0A偏置";break;
    case 3 :校准信息 +="220V, 80A, PF=1";break;
    case 4 :校准信息 +="220V, 80A, PF=0.5";break;
    case 5 :校准信息 +="220V, 20A, PF=1";break;
    case 6 :校准信息 +="220V, 20A, PF=0.5";break;
    case 7 :校准信息 +="220V, 5A, PF=1";break;
    case 8 :校准信息 +="220V, 5A, PF=0.5";break;
    case 9 :校准信息 +="220V,漏电流1A";break;
    case 10 :校准信息 +="220V, 2A, PF=0.5, 偏置";break;
    case 11 :校准信息 +="样机恢复出厂参数";break;
    default:break;
    }
   // timer2->stop();
    emit TD4550State(校准信息,true,TD校准步骤);
}

void TD4550SerialThread::检查源输出(QString 接收数据)
{

    if(接收数据=="PARW=00") {检查步骤=1;检查次数=1;}
    if(接收数据=="OUT=00") {检查步骤=1;检查次数=1;}
    qDebug()<<"接收数据"<<接收数据;
    qDebug()<<"检查步骤"<<检查步骤<<"TD4550当前检查次数"<<检查次数;

    if(检查次数)
    {

        int32_t 测量值;
        char 类型='0';
        测量值=天恒转int32(&类型,接收数据);
        qDebug()<<"测量值"<<测量值<<"TTD4550输出.电压A"<<TD4550输出.电压B;

        switch(检查步骤)
        {
        case 1:if(测量值>(TD4550输出.电压A-200) && 测量值<(TD4550输出.电压A+200)){检查步骤++;检查次数=1;};break;
        case 2:if(测量值>(TD4550输出.电压B-200) && 测量值<(TD4550输出.电压B+200)){检查步骤++;检查次数=1;};break;
        case 3:if(测量值>(TD4550输出.电压C-200) && 测量值<(TD4550输出.电压C+200)){检查步骤++;检查次数=1;};break;
        case 4:if(测量值>(TD4550输出.电流A-200) && 测量值<(TD4550输出.电流A+200)){检查步骤++;检查次数=1;};break;
        case 5:if(测量值>(TD4550输出.电流B-150) && 测量值<(TD4550输出.电流B+150)){检查步骤++;检查次数=1;};break;
        case 6:if(测量值>(TD4550输出.电流C-100) && 测量值<(TD4550输出.电流C+100)){检查步骤++;检查次数=1;};break;
        case 7:if(测量值>(TD4550输出.功因A-300) && 测量值<(TD4550输出.功因A+300)){检查步骤++;检查次数=1;};break;
        case 8:if(测量值>(TD4550输出.功因B-300) && 测量值<(TD4550输出.功因B+300)){检查步骤++;检查次数=1;};break;
        case 9:if(测量值>(TD4550输出.功因C-300) && 测量值<(TD4550输出.功因C+300)){检查步骤++;检查次数=1;};break;
        }
    }

    检查次数++;


    if(检查次数>50) {
        sendData(天恒生成帧("OUT|IA=0|IB=0|IC=0"));sleepMsec(200);
        sendData(天恒生成帧("PARW|ACIRG=AUTO"));sleepMsec(200);
        sendData(天恒生成帧("PARW|OUTSW=OFF"));sleepMsec(200);
        emit TD4550State("源输出不正常",false,100); return;
    }
    if(检查步骤>9) {TD4550Step();检查步骤=1;检查次数=1;return;}//6个步骤都检查正常,发送正常信号给主线程

    sleepMsec(500);

    switch(检查步骤)
    {
    case 1:sendData(天恒生成帧("MEAS|UA"));break;
    case 2:sendData(天恒生成帧("MEAS|UB"));break;
    case 3:sendData(天恒生成帧("MEAS|UC"));break;
    case 4:sendData(天恒生成帧("MEAS|IA"));break;
    case 5:sendData(天恒生成帧("MEAS|IB"));break;
    case 6:sendData(天恒生成帧("MEAS|IC"));break;
    case 7:sendData(天恒生成帧("MEAS|PFA"));break;
    case 8:sendData(天恒生成帧("MEAS|PFB"));break;
    case 9:sendData(天恒生成帧("MEAS|PFC"));break;
    }



}




void TD4550SerialThread::openConj(QString comNo,QList<int> comConj)
{

    simpleSerial =new QSerialPort;
    //连接读取串口数据的信号槽
    QObject::connect(simpleSerial,&QSerialPort::readyRead,this,&TD4550SerialThread::waitRead);

    if(!串口状态)//如果串口本线程未打开
    {
        //simpleSerial =new QSerialPort;
        simpleSerial->setReadBufferSize(0);//设置接收缓冲区大小，0是无穷大

    //    qDebug()<<"串口接收到的配置"<<comConj;

        simpleSerial->setPortName(comNo);
        if(simpleSerial->open(QIODevice::ReadWrite))//如果串口能打开
        {
   //         qDebug()<<"样机开始打开串口，已经打开";

//            comNo//设置串口号
//            comConj[0]//设置波特率
//            comConj[1]//设置校验位
//            comConj[2]/设置停止位
//            comConj[3]//设置数据位数
//            comConj[4]//设置流控制

            //设置波特率
            switch (comConj[0])
            {
               case 0:simpleSerial->setBaudRate(QSerialPort::Baud1200);BaudTime=640;break;
               case 1:simpleSerial->setBaudRate(QSerialPort::Baud2400);BaudTime=320;break;
               case 2:simpleSerial->setBaudRate(QSerialPort::Baud4800);BaudTime=160;break;
               case 3:simpleSerial->setBaudRate(QSerialPort::Baud9600);BaudTime=80;break;
               case 4:simpleSerial->setBaudRate(QSerialPort::Baud19200);BaudTime=40;break;//设置波特率为19200
               case 5:simpleSerial->setBaudRate(QSerialPort::Baud38400);BaudTime=30;break;
               case 6:simpleSerial->setBaudRate(QSerialPort::Baud57600);BaudTime=30;break;//只能设57600，不能强设56000；
               case 7:simpleSerial->setBaudRate(QSerialPort::Baud115200);BaudTime=30;break;
               default:break;
            }

            //设置校验位
            switch (comConj[1])
            {
               case 0: simpleSerial->setParity(QSerialPort::NoParity);break;//无校验none
               case 1: simpleSerial->setParity(QSerialPort::OddParity);break;//奇校验odd
               case 2: simpleSerial->setParity(QSerialPort::EvenParity);break;//偶校验even
               case 3: simpleSerial->setParity(QSerialPort::MarkParity);break;//为1,mark
               case 4: simpleSerial->setParity(QSerialPort::SpaceParity);break;//为0,space
               default: break;
            }

            //设置停止位
            switch (comConj[2])
            {
               case 0: simpleSerial->setStopBits(QSerialPort::OneStop); break;//停止位设置为1
               case 1: simpleSerial->setStopBits(QSerialPort::OneAndHalfStop); break;//停止位设置为1.5
               case 2: simpleSerial->setStopBits(QSerialPort::TwoStop); break;//停止位设置为2
               default:break;
            }

            //设置数据位数
            switch (comConj[3])
            {
               case 0:simpleSerial->setDataBits(QSerialPort::Data5);break;
               case 1:simpleSerial->setDataBits(QSerialPort::Data6);break;
               case 2:simpleSerial->setDataBits(QSerialPort::Data7);break;
               case 3:simpleSerial->setDataBits(QSerialPort::Data8);break;//设置数据位8
               default:break;

            }

            //设置流控制
            switch (comConj[4])
           {
               case 0: simpleSerial->setFlowControl(QSerialPort::NoFlowControl);break;//无流控制
               case 1: simpleSerial->setFlowControl(QSerialPort::HardwareControl);break;//硬件控制 (RTS/CTS)
               case 2: simpleSerial->setFlowControl(QSerialPort::SoftwareControl);break;//软件控制 (XON/XOFF)
               default:break;
           }

            串口状态 =1;//为1表示TD4550串口可正常打开
            qDebug()<<"TD4550当前线程,1"<<QThread::currentThread();
        }
        else
        {
            串口状态=3;//为3表示TD4550串口无法打开
            emit TD4550State("TD4550串口无法打开",false,100);
           // simpleSerial->clear();
//            simpleSerial->close();
//            simpleSerial->deleteLater();
            QObject::disconnect(simpleSerial,&QSerialPort::readyRead,this,&TD4550SerialThread::waitRead);
            qDebug()<<"TD4550串口无法打开";
        }
    }
//串口状态=0，未打开
//串口状态=1. 正常打开
//串口状态=2，已关闭
//串口状态=3，无法打开


}

//发送数据到串口
void TD4550SerialThread::sendData(QByteArray data)
{
   qDebug()<<"TD4550发送数据到串口"<<data;
   simpleSerial->write(data);//数据写入到串口中
}

//读取接收到的信息
void TD4550SerialThread::ReadData()
{
    QByteArray buf;
    buf = simpleSerial->readAll();

    if(!buf.isEmpty())//buf读到内容，才会上传数据到窗口,不保证能把数据完全读完
    {
       qDebug()<<"4550接收到数据"<<buf;
       接收数据=天恒还原帧(buf,&错误类型);
       if(TD校准步骤>1) 检查源输出(接收数据);
    }
}

//当&QSerialPort::readyRead发送信号说准备要开始读了，则执行此定时函数，不能用sleep()
void TD4550SerialThread::waitRead()
{
     QTimer::singleShot(BaudTime, this,&TD4550SerialThread::ReadData);
}

